package com.swak.fx.support;

import java.awt.Image;
import java.awt.TrayIcon;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.function.Supplier;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

/**
 * 系统托盘
 * 
 * @author 618lf
 */
public class Tray extends TrayIcon {

	private Stage stage;
	private Supplier<Window> windowBuilder;
	transient MouseListener mouseListener;
	transient MouseLeftClickedListener leftClickedListener;

	public Tray(Image image, String tooltip) {
		super(image, tooltip);
		this.setImageAutoSize(true);
		super.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				super.mouseClicked(e);
				Tray.this.onMouseClicked(e);
			}
		});
		this.addMouseLeftClickedListener((event) -> {
			Display.runUI(() -> {
				Stage primaryStage = Display.getStage();
				if (!primaryStage.isShowing()) {
					primaryStage.show();
				}
				if (primaryStage.isIconified()) {
					primaryStage.setIconified(false);
				}
				primaryStage.toFront();
			});
		});
	}

	/**
	 * 通过自定义界面的方式设置 - 弹出的菜单
	 * 
	 * @param menu
	 */
	public void setMenu(Region menu) {
		if (menu == null || stage != null) {
			return;
		}
		StackPane pane = new StackPane();
		stage = new Stage();
		stage.initOwner(Display.getStage());
		stage.setScene(new Scene(pane));
		// 去掉面板的标题栏
		stage.initStyle(StageStyle.TRANSPARENT);
		// 添加组件到面板中
		pane.getChildren().add(menu);
		// 设置面板的宽高
		stage.setWidth(menu.getPrefWidth());
		stage.setHeight(menu.getPrefHeight());
		this.initStage();
	}

	/**
	 * 指定一个弹出界面 -- 这种方式扩展性更好
	 * 
	 * @param page
	 */
	public void setMenu(Window page) {
		if (page == null || stage != null) {
			return;
		}
		this.stage = page.getStage();
		this.initStage();
	}

	/**
	 * 指定一个弹出界面 -- 这种方式扩展性更好
	 * 
	 * @param page
	 */
	public void setMenu(Supplier<Window> windowBuilder) {
		this.windowBuilder = windowBuilder;
	}

	private void initStage() {
		// 监听面板焦点
		stage.focusedProperty().addListener(new ChangeListener<Boolean>() {
			@Override
			public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
				if (!newValue) {
					// 如果失去焦点就隐藏面板
					stage.hide();
				}
			}
		});
	}

	private void onMouseClicked(MouseEvent e) {
		// 右键点击
		if (e.getButton() == 3) {
			Display.runUI(() -> {
				this.onMouseRightClicked(e);
			});
		}
		// 左键点击
		else if (e.getButton() == 1 && this.leftClickedListener != null) {
			this.leftClickedListener.onMouseClicked(e);
		}
		if (mouseListener != null) {
			mouseListener.mouseClicked(e);
		}
	}

	private void buildStage() {
		if (stage != null || this.windowBuilder == null) {
			return;
		}
		Window menu = this.windowBuilder.get();
		this.setMenu(menu);
	}

	private void onMouseRightClicked(MouseEvent e) {
		this.buildStage();
		if (stage == null) {
			return;
		}

		// height
		double height = stage.getScene().getRoot().prefHeight(-1);

		// 设置dialog的显示位置
		stage.setX(e.getX());
		stage.setY(e.getY() - height);

		// 设置为顶层，否则在windows系统中会被底部任务栏遮挡
		stage.setAlwaysOnTop(true);
		// 展示/隐藏
		if (!stage.isShowing()) {
			stage.show();
		} else {
			stage.hide();
		}
	}

	@Override
	public synchronized void addMouseListener(MouseListener listener) {
		this.mouseListener = listener;
	}

	public synchronized void addMouseLeftClickedListener(MouseLeftClickedListener listener) {
		this.leftClickedListener = listener;
	}

	@FunctionalInterface
	public static interface MouseLeftClickedListener {
		void onMouseClicked(MouseEvent e);
	}
}